/**
   \file      Log.hpp
   \brief     Base class for the logging system.
   \author    Marco Siciliano

   LibLog implementation.

   A library to log into several devices.
   Copyright (C) Marco Siciliano 2002 [marco@siciliano.de]

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*! \mainpage liblog
 * is a free logging library written by Marco Siciliano.
 *
 * \section Description
 *
 * This is a free logging library which easily can be extended with new
 * log devices just be inheriting from the CBaseLog class and implementing 
 * the log interface. (See BaseLog.hpp for the interface description).
 * An example is the CConsoleLog logdevice which is already implemented.
 * Please feel free to write your own log devices and if you want you can 
 * mail them to me (marco@siciliano.de).
 */

#ifndef LIB_LOG_HPP
#define LIB_LOG_HPP

#include "Makros.hpp"

#include <string>
#include <list>



class CBaseLog;


/**
   Base class for the logging system. The CLog class is a singleton object and 
   can be seen as the central point of this library.
 
   To be thread safe a pthread mutex is uesed.
 
 
   There are 4 different LOG_MESSAGE_TYPE's:
 
   - DEBUG  : Should be used for debugging purposes only. 
   - MESSAGE: Normal log messages should go here.
   - ERROR  : Error logging should go here.
   - FATAL  : Fatal error logging should go here.
  
   Classes inherited from CBaseLog (BaseLog.hpp) register/unregister to this 
   CLog class.
   If a log messages occures, triggered by an makro call (Makro.hpp) all 
   registered logdevices will be notified threw their notification channels.
   Following notification channels must be implemented by each logdevice:
 
   \verbatim
   void logDebug  (const std::string &eventSource, const std::string &eventLine,
                   const std::string &eventMessage);
   void logMessage(const std::string &eventSource, const std::string &eventLine,
                   const std::string &eventMessage);
   void logError  (const std::string &eventSource, const std::string &eventLine,
                   const std::string &eventMessage);
   void logFatal  (const std::string &eventSource, const std::string &eventLine,
                   const std::string &eventMessage);
   \endverbatim
*/
class CLog 
{ 
    enum LOG_MESSAGE_TYPE { DEBUG, MESSAGE, ERROR, FATAL };

public:
	/// This class uses the singelton pattern. 
    static CLog * instance();
	
	/// Destructor
    virtual ~CLog();

	/// Filtering of messages (not implemented yet).
    void setFilter(unsigned int filter);

   /**
    * Enables/Disables library debug information. 
    * Tbe default is <code>false</code>.
    *
    * @param debug          <code>true</code> enables library debugging,
    *                       <code>false</code> disables library disables.
    *
    */
    void setDebug(bool bDebug) { m_bDebug = bDebug; }

   /**
    * You can easily register your own logdevice by inheriting from CBaseLog  
    * which is declared in BaseLog.hpp header.
    * You just have to implement the four message types for your own logdevice.
    *
    * Note: User can register more than one log device. This library will output
    *       the information to all log devices.
    *
    * @param pLogDevice     Pointer to the logdevice you want to register.
    *                       The memory for the logdevice must be allocated
    *                       on the heap using <code>new</code>.
    *                       The memory will be deleted if you unregister a
    *                       logdevice or while destructing the CLog object.
    *                       Must be inherited from CBaseLog.
    *
    * @return               <code>true</code> if registration was successfull.
    *                       <code>false</code> if registration failed.
    */
    bool registerLogDevice   (CBaseLog *pLogDevice);


   /**
    * Unregister a logdevice. Pass a pointer to logdevice you want to 
    * unregister.
    *
    * @param pLogDevice     Pointer to the logdevice you want to unregister.
    *
    * @return               <code>true</code> if unregistration was successfull.
    *                       <code>false</code> if unregistration failed.
    */
    bool unregisterLogDevice (CBaseLog *pLogDevice);

  
   /**
    * Returns the number of currently registered logdevices.
    *
    * @return               Number of registered logdevices.
    *
    */
    inline unsigned int registeredLogDevices() const { 
        return T_lBaseLogs.size(); 
    }


  
   /**
    * Notify all registered logdevices threw their logDebug notification 
    * channel. This method should not be called directly, instead use the 
    * LOG_DEBUG makro, defined in Makro.hpp.
    *
    * Note: The actual date and timestamp will be added internally and must not
    *       be passed as parameters.
    *
    * @param eventSource    The name of the sourcefile where the log occured.
    * @param eventLine      The line number of the sourcefile where the log 
    *                       occured
    * @param eventMessage   The log message to be displayed.
    *
    */
    void logDebug  (const std::string &eventSource, 
                    const std::string &eventLine, 
        		    const std::string &eventMessage);


   /**
    * Notify all registered logdevices threw their logMessage notification 
    * channel. This method should not be called directly, instead use the 
    * LOG_MESSAGE makro, defined in Makro.hpp.
    *
    * Note: The actual date and timestamp will be added internally and must not 
    *       be passed as parameters.
    *
    * @param eventSource    The name of the sourcefile where the log occured.
    * @param eventLine      The line number of the sourcefile where the log 
    *                       occured
    * @param eventMessage   The log message to be displayed.
    *
    */
    void logMessage(const std::string &eventSource, 
                    const std::string &eventLine, 
        		    const std::string &eventMessage);



   /**
    * Notify all registered logdevices threw their logError notification 
    * channel. This method should not be called directly, instead use the 
    * LOG_ERROR makro, defined in Makro.hpp.
    *
    * Note: The actual date and timestamp will be added internally and must not 
    *       be passed as parameters.
    *
    * @param eventSource    The name of the sourcefile where the log occured.
    * @param eventLine      The line number of the sourcefile where the log 
    *                       occured
    * @param eventMessage   The log message to be displayed.
    *
    */
    void logError  (const std::string &eventSource, 
                    const std::string &eventLine, 
        		    const std::string &eventMessage);


   /**
    * Notify all registered logdevices threw their logFatal notification 
    * channel.
    * 
    *
    * <b>Note</B>: This method should not be called directly, instead use the 
    *       LOG_FATAL makro, defined in Makro.hpp.
    *       The actual date and timestamp will be added internally and must not 
    *       be passed as parameters.
    *
    * @param eventSource    The name of the sourcefile where the log occured.
    * @param eventLine      The line number of the sourcefile where the log 
    *                       occured
    * @param eventMessage   The log message to be displayed.
    *
    */
    void logFatal  (const std::string &eventSource, 
                    const std::string &eventLine, 
        		    const std::string &eventMessage);
    
    /**
     * Increase indent when necessary, such as entering a function.
     */
    void indent();
    void unindent();

private:
    CLog();

    inline const std::string buildMessage(const std::string &eventSource, 
					                      const std::string &eventLine, 
                    					  const std::string &eventMessage, 
					                      CLog::LOG_MESSAGE_TYPE logDeviceType);
 
    bool getMicroSeconds(long &microsec);
    bool getDateAndTime(std::string &strDateTime);

private:
    static CLog *s_pInstance;

private:
    typedef std::list<CBaseLog *>           BaseLogs;
    typedef std::list<CBaseLog *>::iterator BaseLogIterator;

    BaseLogs        T_lBaseLogs;
    BaseLogIterator T_itBaseLog;
    
private:
    unsigned int FILTER;
    bool m_bDebug; // used to debug CLog itself
    unsigned int m_layer;
};


#endif

